import { Injectable, Injector } from '@angular/core';
import {
  HttpInterceptor,
  HttpHandler,
  HttpRequest,
  HttpResponse,
  HttpSentEvent,
  HttpHeaderResponse,
  HttpProgressEvent,
  HttpUserEvent,
  HttpErrorResponse
} from '@angular/common/http';

import { Observable, of, throwError } from 'rxjs';

import { tap, mergeMap, catchError } from 'rxjs/operators';

import { environment } from '@env/environment';

import { NzMessageService } from 'ng-zorro-antd';
import { ReturnMessage } from './return-message';

import { ReturnDataSet } from '../model/returnDataSet';
import { Constant } from '../constant';

/**
 * 请求拦截器
 */
@Injectable()
export class NetInterceptor implements HttpInterceptor {

  constructor(
    private injector: Injector,
    private returnMessage: ReturnMessage
  ) { }

  private get nzMessage(): NzMessageService {
    return this.injector.get(NzMessageService);
  }

  private handlerError(event: any) {
    return throwError(event);
  }

  private handleData(event: HttpResponse<any> | HttpErrorResponse): Observable<any> {
    let handler = of(event);
    // 业务处理：一些通用操作
    switch (event.status) {
      case 0:
        this.nzMessage.error('网络异常！');
        handler = this.handlerError(event);
        break;
      case 401:
        // 未登录状态码
        this.returnMessage.getLoginTip();
        handler = this.handlerError(event);
        break;
      case 200:
        // 业务层级错误处理
        if (event instanceof HttpResponse) {
          const returnDataSet = this.permissionDataSet(event);
          if (returnDataSet !== null) {
            if (returnDataSet.returnCode !== '000000') {
              const errorInfo = Constant.DATA_SET_ERROR_PREFIX + returnDataSet.returnCode + returnDataSet.errorInfo;
              return throwError(
                new HttpErrorResponse(
                  Object.assign(event, {
                    error: errorInfo
                  })
                )
              );
            }
            event = new HttpResponse(Object.assign(event, { body: returnDataSet.dataSet }));
            handler = of(event);
          }
        } else if (event instanceof HttpErrorResponse) {
          const error = event.error;
          let message = event.message;
          if (error !== null) {
            const prefixLength = Constant.DATA_SET_ERROR_PREFIX.length;
            const errorCodeLength = 6;
            if (error.length >= prefixLength + errorCodeLength) {
              const prefix = error.substring(0, prefixLength);
              if (Constant.DATA_SET_ERROR_PREFIX === prefix) {
                const errorCode = error.substring(prefix.length, prefix.length + errorCodeLength);
                this.returnMessage.verification(errorCode);
                message = errorCode + ' ' + error.substring(prefix.length + errorCodeLength, error.length);
              }
            }
          }
          handler = this.handlerError(message);
        }
        break;
      case 404:
        // 404
        this.nzMessage.error('无效请求');
        handler = this.handlerError(event);
        break;
      default:
        this.nzMessage.error('返回状态码:' + event.status);
        handler = this.handlerError(event);
        break;
    }
    return handler;
  }

  private permissionDataSet(event: any): ReturnDataSet {
    const returnDataSet = event.body as ReturnDataSet;
    return returnDataSet !== null && returnDataSet.returnCode !== undefined ? returnDataSet : null;
  }

  intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any>> {
    // 统一加上服务端前缀
    let url = req.url;
    if (!url.startsWith('https://') && !url.startsWith('http://') && !url.startsWith('assets')) {
      url = environment.serverUrl + url;
    }
    const newReq = req.clone({
      url: url
    });
    const started = Date.now();
    return next.handle(newReq)
      .pipe(
        tap(event => {
          // 请求过程
          if (event instanceof HttpResponse) {
            const elapsed = Date.now() - started;
            if (!environment.production) {
              console.log(`Request for ${newReq.urlWithParams} took ${elapsed} ms.`);
            }
          }
        }),
        mergeMap((event: any) => {
          // 允许统一对请求错误处理，这是因为一个请求若是业务上错误的情况下其HTTP请求的状态是200的情况下需要
          if (event instanceof HttpResponse && event.status === 200) {
            return this.handleData(event);
          }
          // 若一切都正常，则后续操作
          return of(event);
        }),
        catchError((res: HttpErrorResponse) => {
          return this.handleData(res);
        })
      );
  }
}
